module common.pen;

import std.string;

import share.types;

import allegro5.allegro;
import allegro5.allegro_font;
import allegro5.allegro_ttf;
import allegro5.allegro_primitives;


public class Pen
{
    private enum FONTDIR = "./Fonts/";

    private ALLEGRO_FONT* font = null;


    public void loadFont(in string facename, int size, int flags)
    {
        auto zflname = toStringz(FONTDIR ~ facename ~ ".ttf");
        if (font !is null) return; // already loaded!
        font = al_load_font(zflname, size, flags);
    }
    
    public void unloadFont()
    {
        if (font !is null)
        {
            al_destroy_font(font);
            font = null;
        }
    }

    public int textWidth(in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;
        
        immutable int text_width = al_get_text_width(font, buffer.ptr);
        return text_width;
    }

    public int textHeight(in string str)
    {
        immutable int line_height = al_get_font_line_height(font);
        return line_height;
    }

    public IntPoint measureText(in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;
        
        int text_width = al_get_text_width(font, buffer.ptr);
        int line_height = al_get_font_line_height(font);
        return IntPoint(text_width, line_height);
    }
    
    public void drawText(float x, float y, ALLEGRO_COLOR fcolor, in string str)
    {
        static const ALLEGRO_COLOR TransparentBlack = { r: 0, g: 0, b: 0, a: 0 };
        drawText(x, y, fcolor, TransparentBlack, str);
    }

    public void drawText(float x, float y, ALLEGRO_COLOR fcolor, ALLEGRO_COLOR bcolor, in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;

        // Check transparency - no point drawing if opaque.
        if (bcolor.a != 0)
        {
            auto pt = measureText(str);
            al_draw_filled_rectangle(x, y, x + pt.getX(), y + pt.getY(), bcolor);
        }
        
        al_draw_text(font, fcolor, x, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
    }

    public void drawText(in IntRectangle rc, ALLEGRO_COLOR fcolor, ALLEGRO_COLOR bcolor, in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;
        
        auto pt = measureText(str);
        float x, y;
        
        // Calculate center of rectangle..
        x = rc.getLeft() + (rc.getWidth() / 2) - (pt.getX() / 2);
        y = rc.getTop() + (rc.getHeight() / 2) - (pt.getY() / 2);

        // Check transparency - no point drawing if opaque.
        if (bcolor.a != 0)
        {
            al_draw_filled_rectangle(x, y, x + pt.getX(), y + pt.getY(), bcolor);
        }
        
        al_draw_text(font, fcolor, x, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
    }

    public void drawShadowText(float x, float y, ALLEGRO_COLOR fcolor, ALLEGRO_COLOR bcolor, in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;
        
        al_draw_text(font, bcolor, x+1, y+1, ALLEGRO_ALIGN_LEFT, buffer.ptr);
        al_draw_text(font, fcolor, x, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
    }
    
    public void drawTextUnderline(float x, float y, ALLEGRO_COLOR fcolor, in string str)
    {
        const lineOffset = 0.1f;
        const lineThickness = 1.0f;

        auto pt = measureText(str);

        drawText(x, y, fcolor, str);
        al_draw_line(x - 0.5f, y + pt.getY(), x + pt.getX() - 0.5f, y + pt.getY(), fcolor, lineThickness);
    }
    
    public void drawBoldText(float x, float y, ALLEGRO_COLOR fcolor, ALLEGRO_COLOR bcolor, in string str)
    {
        static char buffer[1024];
        
        buffer[0 .. str.length] = str[0 .. $];
        buffer[str.length] = 0;
        
        al_draw_text(font, bcolor, x - 1, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
        al_draw_text(font, bcolor, x + 1, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
        al_draw_text(font, bcolor, x, y - 1, ALLEGRO_ALIGN_LEFT, buffer.ptr);
        al_draw_text(font, bcolor, x, y + 1, ALLEGRO_ALIGN_LEFT, buffer.ptr);
        
        al_draw_text(font, fcolor, x, y, ALLEGRO_ALIGN_LEFT, buffer.ptr);
    }
    
    public bool divideString(int nDivideWidth, ref int nDividedLine, in string source, ref string destination)
    {
        const max_line = 255;
        const div_char = '`';
        static char buffer[max_line * 2];
        string szTmpCheck;
        
        nDividedLine = 1;
        
        int nStartLen   = 0;
        int nEndLen     = 0;
        int nResultLen  = 0;
        
        int nWordCheck  = 0;
        
        if ( source.length == 0 )
            return false;
        
        //buffer.length = max_line * 2;
        destination.length = 0;
        
        for ( int nCnt = 0; nCnt < source.length; nCnt++)
        {
            nEndLen = nCnt+1;
            
            // ¸¸¾à¿¡ ±ÛÀÚÅ©±â°¡ ÃÖ´ë ±ÛÀÚÅ©±â¸¦ ³Ñ¾î°¡¸é ÃÖ´ëÄ¡·Î ¸ÂÃçÁØ´Ù.
            if ( nEndLen >= max_line )
            {
                buffer[max_line-1] = '\0';
                break;
            }
            
            // ÇöÀçºÎºÐ±îÁöÀÇ ¹®ÀÚ¿­À» ÀÐ´Â´Ù.
            szTmpCheck = source[nStartLen .. nStartLen+(nEndLen-nStartLen)];     
            IntPoint pt = measureText(szTmpCheck);
            
            // ÇöÀç±îÁö ÀÐ¾î¿Â ºÎºÐÀÌ Çã¿ë³ÐÀÌ¸¦ ³Ñ¾î¼¹À»¶§.
            if ( pt.getX() > nDivideWidth )
            {
                // ÇöÀç 2¹ÙÀÌÆ® ¹®ÀÚ¶ó¸é. 
                if ( source[nEndLen-1] < 0 )
                {
                    // ÇöÀç ¾Õ¿¡¹®ÀÚ°¡ 2¹ÙÀÌÆ® ¹®ÀÚ°¡ ¾Æ´Ï¶ó¸é
                    if ( !(nWordCheck%2) )
                    {
                        nStartLen += szTmpCheck.length - 1;
                        nCnt--;
                        buffer[nResultLen] = div_char;
                        nResultLen++;
                        nDividedLine++;
                    }
                    else
                    {
                        nStartLen += szTmpCheck.length - 2;
                        nCnt -= 2;
                        buffer[nResultLen-1] = div_char;
                        nDividedLine++;
                        nWordCheck--;
                    }
                }
                // 1¹ÙÀÌÆ® ¹®ÀÚ. 
                // ÇöÀçº¸´Ù ÇÑ¹ÙÀÌÆ®¾ÕºÎºÐ±îÁö¸¸ °í·ÁÇØÁÖ¸é µÈ´Ù.
                else
                {
                    nStartLen += szTmpCheck.length - 1;
                    nCnt--;
                    buffer[nResultLen] = div_char;
                    nResultLen++;
                    nDividedLine++;
                }
            }
            else
            {
                if ( source[nEndLen-1] < 0 )
                    nWordCheck++;
                
                buffer[nResultLen] = source[nEndLen-1];
                nResultLen++;
            }
        }
        
        if (nResultLen > 0)
        {
            //destination = buffer.idup;
            //destination.length = nResultLen;
            destination = buffer[0 .. nResultLen].idup;
        }
        
        return true;
    }
}

